/*
 * Author: Dennis Feng
 * Created: 12 April 2012
 * 
 * Summary: Main activity for MemoPad GPS. All other activities return to this
 * activity.
 */

package sfsu.memopad;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.Spinner;
import android.widget.Toast;

public class MemoPadActivity extends Activity {
	// Activity Id Numbers.
	private static final int UPDATE = 0;
	private static final int ACTIVITY_CREATE = 1;
	private static final int ACTIVITY_EDIT = 2;
	private static final int LOGIN_ACTIVITY = 3;
	private static final int NEW_GROUP = 4;
	private static final int NETWORK_ADD = 5;
	private static final int NETWORK_DELETE = 6;
	
	// Menu Id Numbers.
	private static final int INSERT_ID = Menu.FIRST;
	private static final int DELETE_ID = Menu.FIRST + 1;
	private static final int DELETE_MSG = Menu.FIRST + 2;
	private static final int LOGIN_ID = Menu.FIRST + 3;
	
	// Task View Numbers.
	private static final int ACTIVE_TASKS = 0;
	private static final int COMPLETED_TASKS = 1;

	// Layout objects.
	private Button userNameButton;
	private ImageButton addButton;
	private ImageButton addGroupButton;
	
	// Gesture control variables.
	protected static final int LARGE_MOVE = 60;
	final SwipeDetector swipeDetector = new SwipeDetector();

	// Global variables.
	public static String passData;
	private String userName = "";
    private static int lastIndex;
	private ListView taskListView;
	public static ArrayList<TaskData> taskListData = new ArrayList<TaskData>(); // Array of user's tasks.
	private TaskListAdapter adapter;
	private boolean showOnlyCompletedTasks = false;
	private int activity;
	
	private String webAddress = "http://thecity.sfsu.edu:9226/";
	private String localHost = "http://10.0.2.2:9226/";
	//private String localComputer = "http://192.168.111.151:9226/";
	public static String server;
	
	Intent proximityIntent;
	
	public static final String PREFS_NAME = "MyPrefsFile";

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.notes_list);

		getPreferences();
		checkLogin();
	    
		// Start GPS service.
		proximityIntent = new Intent(MemoPadActivity.this, GpsService.class);
		 
		server = localHost;
		adapter = new TaskListAdapter(this, R.layout.listview_item_row,	taskListData);

		taskListView = (ListView) findViewById(R.id.taskListView);

		View header = (View) getLayoutInflater().inflate(R.layout.listview_header_row, null);
		taskListView.addHeaderView(header);
		taskListView.setAdapter(adapter);
		registerForContextMenu(taskListView);

		updateList();
		
		userNameButton = (Button) findViewById(R.id.ownerNameButton);
		userNameButton.setText(userName + "'s ");

		addButton = (ImageButton) findViewById(R.id.addTaskButton);
		addGroupButton = (ImageButton) findViewById(R.id.addGroupButton);
		
		// Spinner used for switching between Active Tasks and Completed Tasks.
		Spinner spinner = (Spinner) findViewById(R.id.taskSpinner);
	    spinner.setOnItemSelectedListener(new MyOnItemSelectedListener());
		
		// Send user to login screen.
		userNameButton.setOnClickListener(new View.OnClickListener() {
			public void onClick(View view) {
				goToLogin();
			}
		});
		
		// Add a new task.
		addButton.setOnClickListener(new View.OnClickListener() {
			public void onClick(View view) {
				createNewTask();
			}
		});
		
		// Add a new group task.
		addGroupButton.setOnClickListener(new View.OnClickListener() {
			public void onClick(View view) {
				createNewGroupTask();
			}
		});

		// Let's list be able to handle fling gestures.
		taskListView.setOnTouchListener(swipeDetector);
		
		// Selecting a task on the list goes to edit that task.
		taskListView.setOnItemClickListener(new OnItemClickListener() {
			public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
				if (swipeDetector.swipeDetected()) {
					// do the onSwipe action
					deleteTask(position-1);
				} else {
					// do the onItemClick action
					goToEditTask(position - 1);
				}
			}
		});
	}

	// Menu created when you push the menu button.
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);
		menu.add(0, INSERT_ID, 0, R.string.menu_insert);
		menu.add(0, DELETE_MSG, 1, R.string.menu_delete);
		menu.add(0, LOGIN_ID, 2, R.string.login);
		//menu.add(0, UPDATE_ID, 3, R.string.update);
		
		return true;
	}

	// Actions for when a menu item is selected.
	@Override
	public boolean onMenuItemSelected(int featureId, MenuItem item) {
		switch (item.getItemId()) {
		case INSERT_ID: // Add a new note
			createNewTask();
			return true;
		case DELETE_MSG: // Gives user a message on how to delete list item.
			Toast.makeText(getBaseContext(), "Touch & hold on item you wish to delete.", Toast.LENGTH_LONG).show();
			return true;
		case LOGIN_ID:
			goToLogin();
			return true;
		//case UPDATE_ID:
		//	updateList();
		//	return true;
		}
		return super.onMenuItemSelected(featureId, item);
	}

	// Create a context menu. Only option created is to delete list item.
	@Override
	public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
		super.onCreateContextMenu(menu, v, menuInfo);
		menu.add(0, DELETE_ID, 0, R.string.menu_delete);
	}

	// Handle context menu selection. Only option handled is to delete a list
	// item.
	@Override
	public boolean onContextItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case DELETE_ID:
			AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
			int position = (int) info.id;
			deleteTask(position);
			return true;
		}
		return super.onContextItemSelected(item);
	}

	/*
	 * Processes what happens after returning from a network call.
	 */
	protected void onNetworkResult() {
		switch (activity) {
		case UPDATE:
			clearTaskList();
			refreshTaskList(passData);
			break;
		case NETWORK_ADD:
			updateList();
			break;
		case NEW_GROUP:
			Intent intent = new Intent(this, GroupEdit.class);
			intent.putExtra("PASSDATA", passData);
			intent.putExtra("USERNAME", userName);
			Log.d("MemoPad", "passData = " + passData);
			Log.d("MemoPad", "Going to GroupEdit.");
			startActivityForResult(intent, ACTIVITY_EDIT);
			break;
		}
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
		// super.onActivityResult(requestCode, resultCode, intent);
		String passData;

		switch (requestCode) {
		case ACTIVITY_CREATE:
			passData = intent.getExtras().getString("PASSDATA");
			taskListData.add(new TaskData(passData));
			adapter.notifyDataSetChanged();

			taskListData.get(taskListData.size() - 1).setOwner(userName);

			activity = NETWORK_ADD;
			new NetworkCall().execute(server + "ADD<CMD>" + userName + "<CMD>" + convertStringForNetworkSend(passData));
			break;
		case ACTIVITY_EDIT:
			passData = intent.getExtras().getString("PASSDATA");
			updateTaskList(lastIndex, passData);
			
			//Toast.makeText(getBaseContext(), "Item Edited.\nSend edits to server.", Toast.LENGTH_LONG).show();
			activity = NETWORK_ADD;
			new NetworkCall().execute(server + "EDIT<CMD>" + userName + "<CMD>" + convertStringForNetworkSend(passData));
			updateService();
			break;
		case LOGIN_ACTIVITY:
			String name = intent.getExtras().getString("USERNAME");
			if (!name.contentEquals("None")) {
				userNameButton.setText(name + "'s ");
				userName = name;
				setPreferences(userName);
				updateList();
			}
			break;
		}
	}

	/*
	 * These functions handle the tasks local data.
	 */
	// Update tasks from at the index location.
	private void updateTaskList(int index, String newData) {
		taskListData.get(index).parseString(newData);
		adapter.notifyDataSetChanged();
	}
	
	private void updateService() {
		//if(!showOnlyCompletedTasks) { // If true, mean current view is Completed Tasks.
			String locationData = "";
			
			for(int x = 0; x < taskListData.size(); x++) {
				if(taskListData.get(x).isNotificationOn()) {
					locationData += taskListData.get(x).toString();
				}
			}
			
			proximityIntent.setAction(locationData);
			startService(proximityIntent);
		//}
	}

	// Clears the screen of all tasks.
	private void clearTaskList() {
		taskListData.clear();
		adapter.notifyDataSetChanged();
	}

	// Refresh task list.
	private void refreshTaskList(String newData) {
		if (!newData.contentEquals("")) {
			String parts[] = newData.split("<taskbreak>");
			for (int x = 0; x < parts.length; x++) {
				taskListData.add(new TaskData(parts[x]));
			}
			updateService();
			cleanTaskList();
			adapter.notifyDataSetChanged();
		}
	}
	
	// Removes either Active Tasks or Completed Tasks depending on the flag showOnlyCompletedTasks.
	private void cleanTaskList() {
		int x = 0;
		while (x < taskListData.size()) {
			if(showOnlyCompletedTasks) {
				if(!taskListData.get(x).isTaskCompleted()) {
					taskListData.remove(x--);
				}
			} else {
				if(taskListData.get(x).isTaskCompleted()) {
					taskListData.remove(x--);
				}
			}
			x++;
		}
	}

	private String convertStringForNetworkSend(String input) {
		return input.replace("\n", "<CR>");
	}

	/*
	 * Updates list. Send an update request to the server.
	 */
	private void updateList() {
		activity = UPDATE;
		new NetworkCall().execute(server + "UPDATE<CMD>" + userName);
	}

	// Proximity check calls tasks to edit.
	public void proximityCheckCallsTask(int id) {
		goToEditTask(0);
	}

	/*
	 * Create a new task.
	 */
	private void createNewTask() {
		Intent intent = new Intent(this, NoteEdit.class);
		intent.putExtra("PASSDATA", "");
		intent.putExtra("USERNAME", userName);
		startActivityForResult(intent, ACTIVITY_CREATE);
	}
	
	/*
	 * Create a new group task.
	 */
	private void createNewGroupTask() {
		activity = NEW_GROUP;
		new NetworkCall().execute(server + "NEWGROUP<CMD>" + userName + "<CMD>");
	}

	/*
	 * Send the user to NoteEdit.
	 */
	private void goToEditTask(int index) {
		Intent intent;
		if(taskListData.get(index).getGroupID() < 0) {
			intent = new Intent(this, NoteEdit.class);
		} else {
			intent = new Intent(this, GroupEdit.class);
		}
		
		lastIndex = index; // Set index for return.
		intent.putExtra("PASSDATA", taskListData.get(index).toString());
		intent.putExtra("USERNAME", userName);
		startActivityForResult(intent, ACTIVITY_EDIT);
	}

	/*
	 * Delete task from list and from server.
	 */
	public void deleteTask(int position) {
		int removeID = taskListData.get(position).getTaskId();
		activity = NETWORK_DELETE;
		
		if(removeID == -1) {
			removeID = taskListData.get(position).getGroupID();
			new NetworkCall().execute(server + "GROUPDELETE<CMD>" + userName + "<CMD>" + removeID);
		} else {
			new NetworkCall().execute(server + "DELETE<CMD>" + userName + "<CMD>" + removeID);	
		}
		taskListData.remove(position);
		adapter.notifyDataSetChanged();
		updateService();
	}
	
	public void switchTaskView(int view) {
		switch(view) {
		case ACTIVE_TASKS:
			showOnlyCompletedTasks = false;
			break;
		case COMPLETED_TASKS:
			showOnlyCompletedTasks = true;
			break;
		}
		updateList();
	}

	/*
	 * Send user to login screen.
	 */
	private void goToLogin() {
		Intent intent = new Intent(this, Login.class);
		startActivityForResult(intent, LOGIN_ACTIVITY);
	}
	
	/*
	 * Set preferences.
	 */
	private void setPreferences(String input) {
		SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
        SharedPreferences.Editor editor = settings.edit();
        editor.putString("USERNAME", input);
        editor.commit();
        Log.d("MemoPad", "Setting USERNAME = " + input);
	}
	
	/*
	 * Get preferences.
	 */
	private void getPreferences() {
	    SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
	    userName = settings.getString("USERNAME", "NONE");
	    Log.d("MemoPad", "User: " + userName + " signed on.");
	}
	
	/*
	 * Save preferences.
	 */
	private void savePreferences() {
		SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
        SharedPreferences.Editor editor = settings.edit();
        editor.putString("USERNAME", userName);
        editor.commit();
        Log.d("MemoPad", "Setting USERNAME = " + userName);
	}
	
	/*
	 * Verify login.
	 */
	private void checkLogin() {
		if(userName.contentEquals("NONE")) {
			setPreferences("DF");
			userName = "DF";
			finish();
		}
	}
	
	@Override
	public void onResume() {
		super.onResume();
		getPreferences();
	}
	
	@Override
    public void onStop() {
        super.onStop(); 
        savePreferences();
    }
	
	@Override
    public void onDestroy() {
        super.onDestroy();
        savePreferences();
        Log.d("MemoPad", "Destroyed.");
    }
	
	/*
	 * Network Tasks
	 */
	public class NetworkCall extends AsyncTask<String, Void, String> {
		@Override
		protected void onPreExecute() {
			Log.i("AsyncTask", "onPreExecute");
		}

		/*
		 * Opens a Http connection to a server.
		 */
		private InputStream OpenHttpConnection(String urlString) throws IOException {
			InputStream in = null;
			int response = -1;

			try {
				URL url = new URL(urlString);
				URLConnection conn = url.openConnection();

				if (!(conn instanceof HttpURLConnection))
					throw new IOException("Not an HTTP connection");
				try {
					HttpURLConnection httpConn = (HttpURLConnection) conn;
					httpConn.setAllowUserInteraction(false);
					httpConn.setInstanceFollowRedirects(true);
					httpConn.setRequestMethod("GET");
					httpConn.connect();
					response = httpConn.getResponseCode();
					if (response == HttpURLConnection.HTTP_OK) {
						in = httpConn.getInputStream();
					}
				} catch (Exception ex) {
					Log.d("Networking", ex.getLocalizedMessage());
					throw new IOException("Error connecting");
				}
			} catch (MalformedURLException e) {
				Log.d("Networking", "Error opening URL: " + e);
			}
			return in;
		}

		/*
		 * Pulls string from server.
		 */
		private String DownloadText(String URL) {
			int BUFFER_SIZE = 2000;
			InputStream in = null;
			try {
				in = OpenHttpConnection(URL);
			} catch (IOException e) {
				Log.d("NetworkingActivity", e.getLocalizedMessage());
				return "";
			}

			InputStreamReader isr = new InputStreamReader(in);
			int charRead;
			String str = "";
			char[] inputBuffer = new char[BUFFER_SIZE];
			try {
				while ((charRead = isr.read(inputBuffer)) > 0) {
					// ---convert the chars to a String---
					String readString = String.copyValueOf(inputBuffer, 0, charRead);
					str += readString;
					inputBuffer = new char[BUFFER_SIZE];
				}
				in.close();
			} catch (IOException e) {
				Log.d("NetworkingActivity", e.getLocalizedMessage());
				return "";
			}
			return str;
		}

		// Set up DownloadText as occurs in the background.
		@Override
		protected String doInBackground(String... urls) {
			Log.i("NetworkCall", "doInBackgroup: " + urls);
			return DownloadText(urls[0]);
		}

		/*
		 * On completion of Async task, the string pulled from the server is
		 * saved in passData.
		 */
		@Override
		protected void onPostExecute(String result) {
			passData = result;
			onNetworkResult();
		}
	}
	
	/*
	 * Used for task spinner that switches between Active Tasks and Completed Tasks.
	 */
	public class MyOnItemSelectedListener implements OnItemSelectedListener {
	    public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
	    	if (parent.getItemAtPosition(pos).toString().contentEquals("Completed Tasks")) {
	    		switchTaskView(COMPLETED_TASKS);
	    	} else {
	    		switchTaskView(ACTIVE_TASKS);
	    	}
	    }

	    public void onNothingSelected(AdapterView parent) {
	      // Do nothing.
	    }
	}
}